﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.Threading;
using JigLibX.Physics;
using JigLibX.Collision;
using JigLibX.Geometry;
using Microsoft.Xna.Framework.Input.Touch;
using Services;
using Utilities;

namespace WAS.Logic.SampleLevel
{

    using Geometry = Body;
    using Game = Microsoft.Xna.Framework.Game;

    using Nuke = Projectile;
    using NukeData = ProjectileData;

    public abstract class BossLayer : BaseLevel
    {
        static protected readonly float ENEMY_MAX_SPEED = 1.0f;

        public BossLayer(Game game, BaseLevelStats current_score, int num_lives)
            : base(game, current_score, num_lives)
        {
        }

        ConfigurationService ships_config;
        public override void Initialize()
        {
            ships_config = Game.Services.GetService(typeof(ConfigurationService)) as ConfigurationService;
            base.Initialize();
        }

        /// <summary>
        /// Per far esplodere una nave dobbiamo:
        /// * toglierla dalla fisica
        /// * aggiungere l'esplosione
        /// </summary>
        protected void ExplodeShipAt(int index)
        {
            var p = CurrentState.bosses[index];
            physics.RemoveBody(p.geometry);
            NewExplosions.Add(new Explosion(true)
            {
                explosion_type = ExplosionType.Ship,
                originating_ship = p.OwnValue,
                position = p.geometry.Position,
            });
            if (CurrentState.slow_motion_timer == 0)
                audio_service.OnNukeExplode(1);
            else
                audio_service.OnNukeExplode(4);

            if (p.ship_description.ShockWaveOnExplode)
            {
                ShootShockWave(p.geometry.Position,
                    p.faction,
                    p.ship_description.ShockWaveData.initialColor,
                    p.ship_description.ShockWaveData.finalColor,
                    p.geometry.Mass / 500,
                    p.ship_description.ShockWaveData.speed,
                    p.ship_description.ShockWaveData.damage,
                    p,
                    false
                );
            }
        }

        protected override Ship CreateBoss(Vector3 position, BoundingSphere bounding_sphere, float mass, ShipType ship_type, Faction faction)
        {
            var sub_volumes = scene_service[ship_type].VolumesSeq;

            var new_boss = new Ship(true) // invochiamo il costruttore che prende un booleano (ignorato, basta non chiamare il costruttore di default)
            {
                stats = new Stats() { CurrentLife = 500.0f, MaxLife = 500.0f },
                geometry = PhysicsHelper.create_spheres(position, bounding_sphere, sub_volumes, mass),
                engines = new Engine[] { },
                faction = faction,
                ship_type = ship_type,
                ship_description = ships_config[ship_type]
            };
            new_boss.AdjustLifeByLevel();

            new_boss.geometry.ExternalData = new_boss;

            new_boss.engines = new[]{
                new Engine(true)
                {
                    Location = Vector3.Backward * 1.1f - Vector3.Right * 0.2f,
                    Throttle = 0.0f
                },
                new Engine(true)
                {
                    Location = Vector3.Backward * 1.1f + Vector3.Right * 0.1f,
                    Throttle = 0.0f
                }
            };

            return new_boss;
        }

        ArrayList<Body> next_others = new ArrayList<Geometry>(25);
        protected override void UpdateBoss(float dt)
        {
            // Aggiorniamo i boss (sparo e movimento)
            for (int i = 0; i < CurrentState.bosses.Count; i++)
            {
                var b = CurrentState.bosses[i];

                next_others.Clear();
                for (int j = i + 1; j < CurrentState.bosses.Count; j++)
                {
                    next_others.Add(CurrentState.bosses[j].geometry);
                }

                b.Update(dt, CurrentState.bosses[i].ship_description.Speed);


                b.stats = new Stats() { MaxLife = b.stats.MaxLife, CurrentLife = b.stats.CurrentLife - ShockWaveDamage(b.geometry.Position, b.faction) };
                if (b.stats.CurrentLife <= 0.0f)
                {
                    ExplodeShipAt(i);
                    OnShipDestroyed(b);
                    CurrentState.RemoveBossAt(i);
                    i--;
                    continue;
                }

                CurrentState.bosses[i] = b;
            }
        }
        
        protected abstract void OnShipDestroyed(Ship ship);

        protected abstract float ShockWaveDamage(Vector3 position, Faction faction);

        protected abstract void ShootShockWave(Vector3 position, Faction faction, Color initialColor, Color finalColor, float range, float speed, float damage, Ship shooter);
        protected abstract void ShootShockWave(Vector3 position, Faction faction, Color initialColor, Color finalColor, float range, float speed, float damage, Ship shooter, bool audio);
    }
}
